package mock

import (
	"context"
	"fmt"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/user/rpc/userclient"

	wechat "github.com/silenceper/wechat/v2"
	"github.com/silenceper/wechat/v2/cache"
	miniConfig "github.com/silenceper/wechat/v2/miniprogram/config"
	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type LoginLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
	return &LoginLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *LoginLogic) Login(
	req *types.MockLoginReq,
	headers *[]*types.Header,
	ip string,
) (resp *types.MockLoginResp, err error) {
	if req.LoginMethod == nil || len(strings.TrimSpace(*req.LoginMethod)) == 0 {
		return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
	}

	var data *types.MockLoginInfo

	switch strings.TrimSpace(*req.LoginMethod) {
	case "wechat_app", "wechat_work_app":
		if req.Code == nil || len(strings.TrimSpace(*req.Code)) == 0 {
			return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
		}

		data, err = l.wxMiniLogin(strings.TrimSpace(*req.Code), ip)
	case "wechat_mobile":
		if req.Mobile == nil || len(strings.TrimSpace(*req.Mobile)) == 0 {
			return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
		}

		data, err = l.wechatMobileLogin(strings.TrimSpace(*req.Mobile), ip)
	case "mobile_vcode":
		if req.Mobile == nil || len(strings.TrimSpace(*req.Mobile)) == 0 {
			return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
		}
		if req.Code == nil || len(strings.TrimSpace(*req.Code)) == 0 {
			return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
		}

		data, err = l.mobileLogin(strings.TrimSpace(*req.Mobile), strings.TrimSpace(*req.Code), ip)
	case "account_password":
		if req.UserName == nil || len(strings.TrimSpace(*req.UserName)) == 0 {
			return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
		}
		if req.Password == nil || len(strings.TrimSpace(*req.Password)) == 0 {
			return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
		}

		data, err = l.accountLogin(strings.TrimSpace(*req.UserName), strings.TrimSpace(*req.Password), ip)
	default:
		return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
	}
	if err != nil {
		return nil, err
	}

	now := time.Now().Unix()
	accessExpire := l.svcCtx.Config.Auth.AccessExpire
	var securityStatus string
	switch int32(data.Status) {
	case globalkey.StatusDisabled:
		securityStatus = jwt.SUSPENDED
	case globalkey.StatusExpired:
		securityStatus = jwt.CANCELLED
	case globalkey.StatusDeleted:
		securityStatus = jwt.BANNED
	case globalkey.StatusAsGuest:
		securityStatus = jwt.ANONYMOUS
	default:
		securityStatus = jwt.CERTIFICATED
	}

	token, err := jwt.NewJwtToken(
		l.svcCtx.Config.Auth.AccessSecret,
		now,
		accessExpire,
		jwt.WithOption("userId", data.UserId),
		jwt.WithOption("rankId", data.RankId),
		jwt.WithOption("role", data.Role),
		jwt.WithOption("securityStatus", securityStatus),
	)
	if err != nil {
		logx.Errorw("Login NewJwtToken err", logx.Field("detail", err.Error()))
		return nil, resultx.NewErrCode(resultx.USER_LOGIN_WXMINI_FAILED)
	}

	var respHeaders []*types.Header
	respHeaders = append(respHeaders, &types.Header{
		Key:   "authorization",
		Value: token,
	})
	*headers = respHeaders

	return &types.MockLoginResp{
		Success: true,
	}, nil
}

func (l *LoginLogic) wxMiniLogin(code string, ip string) (resp *types.MockLoginInfo, err error) {
	miniprogram := wechat.NewWechat().GetMiniProgram(&miniConfig.Config{
		AppID:     l.svcCtx.Config.WxMiniConf.AppId,
		AppSecret: l.svcCtx.Config.WxMiniConf.Secret,
		Cache:     cache.NewMemory(),
	})
	authRes, err := miniprogram.GetAuth().Code2Session(code)
	if err != nil {
		logx.Errorw("Login wxMiniLogin Code2Session err", logx.Field("detail", err.Error()))
		// invalid code, rid: 63958a6e-5f7f3367-50c2f2d5
		// code been used, rid: 6396b5fe-76b76b6d-00c4a74f
		// Code2Session error : errcode=40029 , errmsg=invalid code, rid: 65d9d79d-2a5c278d-3e230b3d
		return nil, resultx.NewErrCode(resultx.USER_LOGIN_WXMINI_FAILED)
	}

	if authRes.ErrCode != 0 || len(authRes.OpenID) == 0 {
		logx.Errorw("Login wxMiniLogin Code2Session failed", logx.Field("detail", fmt.Sprintf("%+v ", authRes)))
		// CommonError:{apiName: ErrCode:0 ErrMsg:}
		// CommonError:{apiName: ErrCode:40163 ErrMsg:code been used, rid: 6396b5fe-76b76b6d-00c4a74f}
		return nil, resultx.NewErrCode(resultx.USER_LOGIN_WXMINI_FAILED)
	}

	// logrus.Info(fmt.Sprintf("Login wxMiniLogin Code2Session res : %+v ", authRes))
	// OpenID:o-kUG5pMqzsclBbFlUdZNJ2OW4_o
	// SessionKey:FAXeGbFV8dDkEeTtLWaaHw==
	// UnionID:

	var userId string
	var status uint32
	var rankId uint64
	var role uint32
	var platformId uint32 = globalkey.ThirdPartyPlatformWechatMini
	res, err := l.svcCtx.UserRpc.GetUserInfoByAuthKey(l.ctx, &userclient.GetUserInfoByAuthKeyReq{
		PlatformId: pointy.GetPointer(platformId),
		AuthKey:    pointy.GetPointer(authRes.OpenID),
	})
	if err != nil {
		logx.Errorw("Login wxMiniLogin GetUserInfoByAuthKey err", logx.Field("detail", err.Error()))
		// CommonError:{apiName: ErrCode:0 ErrMsg:}
		// CommonError:{apiName: ErrCode:40163 ErrMsg:code been used, rid: 6396b5fe-76b76b6d-00c4a74f}
		return nil, resultx.NewErrCode(resultx.USER_LOGIN_WXMINI_FAILED)
	}

	if res.User == nil || res.User.Id == nil {
		registerRes, err := l.svcCtx.UserRpc.CreateUserAuthInfo(l.ctx, &userclient.TmpUserAuthInfo{
			PlatformId: pointy.GetPointer(platformId),
			Openid:     pointy.GetPointer(authRes.OpenID),
			SessionKey: pointy.GetPointer(authRes.SessionKey),
			CreatedIP:  pointy.GetPointer(ip),
		})

		if err != nil {
			logx.Errorw("Login wxMiniLogin CreateUserAuthInfo err", logx.Field("detail", err.Error()))
			return nil, resultx.NewErrCode(resultx.USER_LOGIN_WXMINI_FAILED)
		}

		if registerRes.Id != nil && len(strings.TrimSpace(*registerRes.Id)) > 0 {
			err = l.createGorseUser(*registerRes.Id)
			if err != nil {
				logx.Errorf("Login wxMiniLogin createGorseUser Error: %+v,userid: %+v", err, *registerRes.Id)
				return nil, err
			}
		}

		userId = *registerRes.Id
		status = *registerRes.Status
		rankId = *registerRes.RankId
		role = *registerRes.Role
	} else if len(*res.User.Id) > 0 {
		userId = *res.User.Id
		status = *res.User.Status
		if res.UserDetail != nil || res.UserDetail.Role != nil {
			role = *res.UserDetail.Role
		}
		if res.UserAccount != nil || res.UserAccount.RankId != nil {
			rankId = *res.UserAccount.RankId
		}
	}

	return &types.MockLoginInfo{
		UserId: userId,
		Status: status,
		RankId: rankId,
		Role:   role,
	}, nil
}

func (l *LoginLogic) wechatMobileLogin(mobile string, ip string) (resp *types.MockLoginInfo, err error) {
	return &types.MockLoginInfo{}, nil
}

func (l *LoginLogic) mobileLogin(mobile string, code string, ip string) (resp *types.MockLoginInfo, err error) {
	return &types.MockLoginInfo{}, nil
}

func (l *LoginLogic) accountLogin(userName string, password string, ip string) (resp *types.MockLoginInfo, err error) {
	return &types.MockLoginInfo{}, nil
}

func (l *LoginLogic) createGorseUser(uid string) error {
	return l.svcCtx.GorseClient.CreateUser(
		l.svcCtx.Config.Query.GorseUrl,
		uid, "", "", "",
	)
}
